package cn.tedu.syn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**本类用于复习多线程编辑实现方案2:implements runnable*/
public class TestRunnable1 {
    public static void main(String[] args) {
        TicketRunnable target = new TicketRunnable();
//        Thread t1 = new Thread(target);
//        Thread t2 = new Thread(target);
//        Thread t3 = new Thread(target);
//        Thread t4 = new Thread(target);
//        t1.start();
//        t2.start();
//        t3.start();
//        t4.start();
        /**Executors是用来创建线程池的工具类
         * 它的常用方法:newFixedThreadPool(int)，这个方法用来创建指定数目的线程池对象
         * 创建出来的线程池对象ExecutorService:用来存储线程的池子，负责:新建、启动、关闭、*/
        //使用Executors工具类创建一个最多有5个线程的线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i <5 ; i++) {
            /**execute()让线程池安排线程来执行业务，每次调用都会安排一个线程对象来干活
             * 注意，这里的干活还是将线程对象加入就绪队列，具体调用哪个，还是要看OS*/
            pool.execute(target);
        }
    }
}
/**1.多线程中出现数据安全问题的原因:多线程程序+有共享数据+多条语句操作共享数据
 * 2.同步锁:相当于给容易出现问题的代码加了一把锁，包裹了所有可能会出现安全问题的代码
 * 加锁之后，就有了同步的效果，但是但是,加锁需要考虑加锁的范围:
 * 不能太大,太大,干啥都得排队,效率低,也不能太小,太小,锁不住,还是会有安全隐患*/
class TicketRunnable implements Runnable{
    int tickets = 100;
    Object o = new Object();
    @Override
    public void run() {
        while (true){
            /**3.同步代码块:synchronized(唯一的锁对象){会出现隐患的代码}
             * 同步代码块可以保证在同一时刻，同一个资源只会被一个线程独享*/
//            synchronized (new Object){}//每次来一个新线程，都会new 一把新锁，不唯一，锁不住
            synchronized (o){//这样子所得类型是Object，只有一把锁，可以锁住
//                synchronized (TicketRunnable.class)//这样也可以
               if (tickets>0){//加一个判断，判断有没有票，没有票就结束循环
                   try {
                       Thread.sleep(10);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread().getName()+"="+tickets--);
               }
                if (tickets<=0)break;
            }
        }
    }
}